/*
* testApp.cpp
*
* Created by Joey van der Bie and Vincent Vijn
* www.vanderBie.net & Vincent.Vijn.me
* With code from Theo Watson, Jesus Gollonet and Diego Diaz
*
* 15-04-2010
* Media Technology - University Leiden
*/

#include "testApp.h"
#include "cv.h"
//#include <crtdbg.h>

// -.-.-.-
struct Portion {

    int x;
    int y;

    int w;
    int h;
    int size;

};
// -.-.-.-
#define WIDTH_CAMERA 640
#define HEIGHT_CAMERA 480

//--------------------------------------------------------------
void testApp::setup(){
	imgW = 320;
    imgH = 240;
    imgColors = 3;

    nRecorded = 0;
    nFramesToRecord = 40;
	nPortions = 40;

    maxFramesToRecord = 1000;
    maxPortions = imgH; // we can't have more portions than vertical pixels

    // if you want to render the slitscan bigger...
    zoom = 1;

	reverse = true;

    // video buffer --------------------------------------------------------

    videoData = new unsigned char *[maxFramesToRecord];
    for (int i = 0; i < maxFramesToRecord; i++){
        videoData[i] = new unsigned char[imgW*imgH*imgColors];
    }

	slitData = new unsigned char *[maxFramesToRecord];
    for (int i = 0; i < maxFramesToRecord; i++){
        slitData[i] = new unsigned char[imgW*imgH*imgColors];
    }


    //portions ---------------------------------------------------------------
    strPortions = new Portion * [maxPortions];

    for (int i = 0; i < maxPortions; i++){
        strPortions[i]     = new Portion;
        strPortions[i]->w  = imgW;

    }


	vid.setVerbose(true);
	vid.initGrabber(WIDTH_CAMERA,HEIGHT_CAMERA);
	delayed.allocate(WIDTH_CAMERA,HEIGHT_CAMERA, GL_RGB);

    verdana.loadFont("verdana.ttf",8, false, true);

	// monoTex
	slitPx = new unsigned char [imgW * imgH * imgColors];
	slitTex.allocate(imgW, imgH, GL_RGB);

	// horiz ----
	horizPw = 20;
	horizPh = 240;
	horizP = new unsigned char [imgW*imgH*imgColors];
	horizPtex.allocate(imgW, imgH, GL_RGB);

	mixedP = new unsigned char [imgW*imgH*imgColors];
	mixedPtex.allocate(imgW, imgH, GL_RGB);


    direction = -1;
    directionLine = 0;
    directionLineVert = 430;
    prevDirectionLine = 0;
    prevDirectionLineVert = 430;


    colorImg.allocate(WIDTH_CAMERA,HEIGHT_CAMERA);
	frame_copy.allocate(WIDTH_CAMERA,HEIGHT_CAMERA);

	hm.allocate(WIDTH_CAMERA,HEIGHT_CAMERA);

	//movieArray[0] = "movies/Filmopname2.mov";
	//movieArray[1] = "movies/8737704.mov";
	//movieArray[2] = "movies/9218673.mov";
	//movieArray[3] = "movies/84586101.mov";
	//movieArray[4] = "movies/4113226.mov";
	//movieArray[5] = "movies/video.mov";
	movieArray[0] = "movies/video.mov";

	moviePos = 0;

	vplay.loadMovie(movieArray[moviePos]);
	vplay.play();

	//	_CrtSetBreakAlloc(230);
}
//--------------------------------------------------------------
void testApp::update(){
// capture the frame ++++++++++++++++++++++++++++++++++++++
    vid.grabFrame();

    vplay.idleMovie();

	if (vid.isFrameNew()){
        int tempY    = imgH;
		int posInImg;
		int posInImgVert;

	    frame_copy.setFromPixels(vid.getPixels(), WIDTH_CAMERA,HEIGHT_CAMERA);
        int tmpDirection = hm.detect( frame_copy )[1];

        if(tmpDirection == 0){
//            if(prevDirectionLine > directionLine){
//                direction = -1;
//                reverse = false;
//            }else if(prevDirectionLine < directionLine){
//                direction = 1;
//                reverse = true;
//            }

            prevDirectionLine = directionLine;
            prevDirectionLineVert = directionLineVert;

            directionLine = (directionLine + direction) % imgH;
            directionLineVert = (directionLineVert + direction) % imgW;
        }else{
             prevDirectionLine = directionLine;
             prevDirectionLineVert = directionLineVert;

	    //	directionLine =  (imgH / HEIGHT_CAMERA) * hm.detect( frame_copy )[1];
//		    directionLineVert = (imgW / WIDTH_CAMERA) * hm.detect( frame_copy )[0];
		    directionLine =  ((float)imgH / HEIGHT_CAMERA) * hm.fInfo[0].y;
		    directionLineVert = ((float)imgW / WIDTH_CAMERA) * hm.fInfo[0].x;

        }

		colorImg.setFromPixels(vid.getPixels(), WIDTH_CAMERA,HEIGHT_CAMERA);
        //unsigned char * currentPixels = ;
        // for every frame, we save the current one to videoData
		memcpy(videoData[nRecorded], vid.getPixels(), imgW*imgH*imgColors);
		memcpy(videoData[nRecorded], vplay.getPixels(), imgW*imgH*imgColors);
		// portion size +++++++++++++++++++++++++++++++++++++++++++++++
		pW = imgW;
		pH = imgH / nPortions;

		// to fill the whole img height...
		// if we have a remainder, we'll have to share it up between portions
		pMod = imgH % nPortions;

		//posInImg = imgW * imgH * imgColors;
		if (!reverse)
			posInImg = 0;
		else
			posInImg = imgW * imgH * imgColors;

        //direction++;
//        if(!faceDetect){
//            directionLine = (directionLine + direction) % imgH;
            //prevDirectionLine = directionLine;


        if(directionLine < 0){
            directionLine = imgH;
        }
        posInImg = imgW * imgColors * directionLine; //position of person or mouse;

//        if(prevDirectionLineVert == directionLineVert){
//            directionLineVert = (directionLineVert + direction) % imgW;
//        }
        if(directionLineVert < 0){
            directionLineVert = imgW;
        }
        posInImgVert = imgColors * directionLineVert;;//imgH * imgColors * directionLineVert;

		int tempSize, tempH;

		// delay in frames between portions
		int frameDiff =  (nFramesToRecord / nPortions); //  this is reversed so it goes from bottom to top.
		int portionFrame;
		for (int i = 0; i < nPortions; i ++) {
			tempH = pH;
			// remainder correction.
			if (pMod > 0) {
				tempH ++;
				pMod--;
			}
			tempSize  = pW * tempH * imgColors;

			// which frame of the videoData are we going to use for this portion?
			portionFrame = (nRecorded - (i*frameDiff))%nFramesToRecord;
			if (portionFrame < 0) portionFrame = nFramesToRecord +portionFrame;

			if (!reverse) {
                posInImg += tempSize;
			} else {
				posInImg -= tempSize;
            }

				//printf("%d ", posInImg);
			if(posInImg > imgW * imgH *imgColors){
                posInImg = 0;
			}else if(posInImg < 0){
                posInImg = imgW * imgH * imgColors;
			}
			//  printf("%d \n", posInImg);
            memcpy(slitPx + posInImg  , videoData[portionFrame]+  (posInImg), tempSize);

			// horiz.
			horizPw = imgW/nPortions;
            //printf("%d ", posInImgVert);
			if(posInImgVert >= imgW *imgColors){
                posInImgVert = 0;
			}else if(posInImgVert < 0){
                posInImgVert = imgW * imgColors;
			}
           // printf("%d \n", posInImgVert);
			for (int j = 0; j < horizPh; j++) {
				memcpy((posInImgVert) + horizP + (j *imgW * imgColors), (posInImgVert) +videoData[portionFrame]+ (j*imgW*imgColors), horizPw * imgColors);
                memcpy((posInImgVert) + mixedP + j *imgW * 3, (posInImgVert) +slitData[portionFrame]+ j*imgW*3, horizPw * 3);
			}
            if(!reverse){
                posInImgVert += (horizPw*3);
			}else{
			    posInImgVert -= (horizPw*3);
			}

			memcpy(slitData[nRecorded], slitPx, imgW*imgH*imgColors);
		}

		slitTex.loadData(slitPx, imgW, imgH, GL_RGB);
		horizPtex.loadData(horizP, imgW, imgH, GL_RGB);
		mixedPtex.loadData(mixedP, imgW, imgH, GL_RGB);

		nRecorded++;
		nRecorded %= nFramesToRecord;
	}
}

//--------------------------------------------------------------
void testApp::draw(){
	ofSetColor(230,230,255);

	ofBackground(1,1,1);

    // draw the preview
	//vid.draw(10,10,320,240);

//    for (int i = 0; i < nPortions; i ++) {
//        strPortions[i]->tex.draw(340, 10 + strPortions[i]->y * zoom, pW*zoom, strPortions[i]->h* zoom);
//    }

    slitTex.draw(imgW + 20, 10, imgW*zoom, imgH*zoom);
    horizPtex.draw(670, 10,imgW*zoom, imgH*zoom);
	mixedPtex.draw(350, 260,imgW*zoom*2, imgH*zoom*2);

    char tempString[255];
	sprintf(tempString,"[ +/- ] --> portions: %i\n[ a/z ] --> frames in buffer: %i\n[ s/x ] --> zoom: %i\n[ r ] --> revert slitscan: %s \n[ f ] --> revert line and slitscan: %i \n[ n ] --> next movie: %d \n\nMade by:\nJoey van der Bie and Vincent Vijn\n\nThanks:\nTheo Watson\nJesus Gollonet\nDiego Diaz", nPortions, nFramesToRecord, zoom, reverse? "true" : "false", direction, moviePos);
	//sprintf(tempString,"\n\nMade by:\nJoey van der Bie and Vincent Vijn \n\nThanks Theo Watson Jesus Gollonet and Diego Diaz");

    ofDrawBitmapString(tempString ,10,290);

    colorImg.draw(10,10, 320, 240);
	hm.draw(imgW,imgH);

        ofSetColor(10,255,50);
		ofNoFill();
        ofSetLineWidth(6);
		ofCircle(350+(directionLineVert+(horizPw/2))*2, 260+(directionLine+(horizPw/2))*2, horizPw);

}


//--------------------------------------------------------------
void testApp::keyPressed  (int key){
	// portions
    if (key=='+') {
        if (nPortions < maxPortions && nPortions < nFramesToRecord) {
            nPortions++;
        }
	}

    if (key=='-') {
        if (nPortions > 1) {
            nPortions--;
        }
    }

    // frames
    if (key == 'a') {
        if (nFramesToRecord < maxFramesToRecord) {
            nFramesToRecord++;
        }
    }

    if (key == 'z') {
        if (nFramesToRecord >nPortions) {
            nFramesToRecord--;
        }
    }

    // zoom
    if (key == 's') {
        if (zoom < 5) {
            zoom ++;
        }

    }

    if (key == 'x') {
        if (zoom > 1) {
            zoom --;
        }
    }
	if (key == 'r') {
		reverse = !reverse;
	}
	if (key == 'f') {
        direction *= -1;
        reverse = !reverse;
	}
	if (key == 'n') {
		moviePos++;
		if (moviePos == sizeof(movieArray)/sizeof(string)) {
			moviePos = 0;
		}
		vplay.loadMovie(movieArray[moviePos]);
		vplay.play();
	}
}

//--------------------------------------------------------------
void testApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void testApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void testApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void testApp::mouseReleased(){

}
